﻿#pragma execution_character_set("utf-8")

#include "xunfei_aiui.h"
#include <QDebug>
#include <QMessageBox>
#define debuglog qDebug()

//配置https访问，win32依赖libcrypto-1_1.dll和libssl-1_1.dll，放在与exe同级目录下
void https_ssl_config(QNetworkRequest& NetworkRequest)
{
    QSslConfiguration config = NetworkRequest.sslConfiguration();
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1SslV3);
    NetworkRequest.setSslConfiguration(config);
}

XunFei_AIUI::XunFei_AIUI(QObject *parent) : QObject(parent)
{
    QAudioFormat format;
    // 设置所需的格式
    format.setSampleRate(16000);    //采样率
    format.setChannelCount(1);  //单通道
    format.setSampleSize(16);    //分辨率
    format.setCodec("audio/pcm");   //编码格式
    format.setByteOrder(QAudioFormat::LittleEndian);    //小端字节顺序
    format.setSampleType(QAudioFormat::UnSignedInt);

    QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    if (!info.isFormatSupported(format))
    {
      qWarning() << "Default format not supported, trying to use the nearest.";
      format = info.nearestFormat(format);
    }
    AudioInput = new QAudioInput(format,this);
    connect(AudioInput, &QAudioInput::stateChanged, this, &XunFei_AIUI::on_AudioInput_stateChange);

    dest_file = new QFile(QString("%1/voice.raw").arg(qApp->applicationDirPath()),this);

    NetAccManager = new QNetworkAccessManager(this);
    connect(NetAccManager, &QNetworkAccessManager::finished, this, &XunFei_AIUI::iFLY_reply);
    https_ssl_config(Request);
}
XunFei_AIUI::~XunFei_AIUI()
{
    if(dest_file->isOpen())
    {
        dest_file->close();
    }
}

void XunFei_AIUI::set_parameters(const QString& app_id, const QString& auth_id, const QString& api_key)
{
    if(!QFile::exists(qApp->applicationDirPath() + "/user.ini"))
    {
        QMessageBox::warning(0,"错误","未找到用户参数文件user.ini，请按以下内容\n[parameters]\napp_id=\nauth_id=\napi_key=\n自行创建并写入自己的应用参数，重新打开本程序");
        emit cmd_close();
        return;
    }
    QSettings Settings(qApp->applicationDirPath() + "/user.ini", QSettings::IniFormat);
    Settings.beginGroup("parameters");
    this->app_id = Settings.value("app_id").toString();
    this->auth_id = Settings.value("auth_id").toString();
    this->api_key = Settings.value("api_key").toString();
    Settings.endGroup();
    if(this->app_id.isEmpty() || this->auth_id.isEmpty() || this->api_key.isEmpty())
    {
        QMessageBox::warning(0,"错误","有参数为空，请检查user.ini文件中的参数");
        emit cmd_close();
    }
}

void XunFei_AIUI::startRecord()
{
    if(!dest_file->open( QIODevice::WriteOnly | QIODevice::Truncate ))  //每次打开先清除原有内容
    {
        debuglog<<"打开文件voice.raw失败。";
        return;
    }
    debuglog<<"开始录音";
    ETimer.start();
    AudioInput->start(dest_file);
}
void XunFei_AIUI::stopRecord()
{
    debuglog<<"结束录音";
    AudioInput->stop();
    dest_file->close();
    int elapsed_ms = ETimer.elapsed();
    debuglog<<"录音时长："<<elapsed_ms<<"毫秒";
    if(elapsed_ms > 1000)
    {
        ask_iFLY();
    }
}
void XunFei_AIUI::on_AudioInput_stateChange(QAudio::State newState)
{
    switch(newState)
    {
    case QAudio::ActiveState:
        debuglog<<"正在处理音频";
//        Record_timer->stop();
        break;
    case QAudio::IdleState:
        debuglog<<"进入空闲状态";
//        Record_timer->start(500);   //用户不说话超过500毫秒，则结束录音
        break;
//    case QAudio::StoppedState:
//        break;
//    case QAudio::SuspendedState://音频流处于挂起状态,在调用suspend()或当另一个流控制音频设备时输入。
//        break;
//    case QAudio::InterruptedState://中断，挂起状态，因为另一个高优先级的流目前控制着音频设备
//        break;
    default:
        break;
    }
}

void XunFei_AIUI::ask_iFLY()
{
    if(!dest_file->open( QIODevice::ReadOnly))
    {
        debuglog<<"打开文件voice.wav失败。";
        QMessageBox::warning(0,"","文件打开错误");
        return;
    }
    QByteArray post_data = dest_file->readAll();    //发送音频
    dest_file->close();

//    QByteArray post_data = QString("贵港天气").toLatin1();    //发送字符串

//    QNetworkRequest Request;
//    https_ssl_config(Request);
    Request.setUrl(QUrl(AIUI_url));
    Request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));

    QByteArray X_Appid = app_id.toUtf8();
    Request.setRawHeader("X-Appid", X_Appid);

    QByteArray X_CurTime = QString::number(QDateTime::currentDateTimeUtc().toTime_t()).toUtf8();
    Request.setRawHeader("X-CurTime", X_CurTime);

    QJsonObject ParamObject;
    ParamObject.insert("scene", "main");
    ParamObject.insert("auth_id", auth_id);
    ParamObject.insert("data_type", "audio");
//    ParamObject.insert("data_type", "text");
    QJsonDocument Document(ParamObject);
    QByteArray X_Param = Document.toJson().toBase64();
    Request.setRawHeader("X-Param", X_Param);

    QByteArray X_CheckSum = QCryptographicHash::hash(api_key.toUtf8()+X_CurTime+X_Param, QCryptographicHash::Md5).toHex();
    Request.setRawHeader("X-CheckSum", X_CheckSum);

    NetAccManager->post(Request,post_data);
}

void XunFei_AIUI::iFLY_reply(QNetworkReply *reply)
{
    if(reply->error() != QNetworkReply::NoError)
    {
        QMessageBox::warning(0, "错误", reply->errorString());
        return;
    }
    QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
    if(doc.object().value("code").toString() == "0")
    {
        QJsonArray arr = doc.object().take("data").toArray();

        emit iat_result(arr.at(0).toObject().take("text").toString());

        if(arr.at(1).toObject().contains("intent"))
        {
            QJsonObject obj = arr.at(1).toObject().take("intent").toObject();
            if(obj.contains("answer"))
            {
                QString answer = obj.take("answer").toObject().take("text").toString();
                if(answer.isEmpty())
                {
                    emit xunfei_answer("我还没有学会这个技能哦！");
                    return;
                }
                else
                {
                    emit xunfei_answer(answer);
                }
            }
            else
            {
                emit xunfei_answer("我还没有学会这个技能哦！");
                return;
            }
            if(obj.contains("data"))
            {
                QJsonArray results = obj.take("data").toObject().take("result").toArray();
                QString resultstr("");
                for(int index = 0; index < results.size(); index++)
                {
                    resultstr.append(results.at(index).toObject().take("description").toString());
                }
                emit xunfei_answer(resultstr);
            }
        }
        else
        {
            emit xunfei_answer("我还没有学会这个技能哦！");
        }
        return;
    }
    emit xunfei_answer("哎呀，好像系统出毛病了！");
    emit err_msg(doc.toJson(QJsonDocument::Indented));
}
